#include "stdafx.h"
#include "CoreXMLHandler.h"
#include "CoreXMLHandlerManager.h"
#include "StanzaHandler.h"
#include "Logger.h"
#include "Packages.h"

#include <assert.h>

namespace ExamSystem
{
    static int nullInterger = 0;

    CCoreXMLHandler::CCoreXMLHandler(CCoreXMLHandlerManager *manager)
        : m_locator(NULL)
        , m_flagStreamStart(false)
        , m_handlerManager(manager)
        , m_currentStanzaHandler(NULL)
        , m_attachedConnection(NULL)
    {

    }

    void CCoreXMLHandler::setDocumentLocator(const Locator* loc)
    {
        m_locator = loc;
    }

    void CCoreXMLHandler::startDocument()
    {

    }

    void CCoreXMLHandler::endDocument()
    {

    }

    void CCoreXMLHandler::startElement(const XMLString& uri, const XMLString& localName, const XMLString& qname, const Attributes& attributes)
    {
        if (!m_flagStreamStart)
        {
            systemLogger.trace("Stream started.");
            if (localName == CPackage::labelExamination)
            {
                m_flagStreamStart = true;
                eventStreamStart(this, nullInterger);
            }
            else
            {
                // this stream is not a valid exam stream
                eventInvalidStream(this, nullInterger);
            }
        }
        else if (localName == CPackage::labelPackage) // a package
        {
            //systemLogger.trace("Package: " + attributes.getValue(CPackage::namespaceURI, CPackage::attributeType) /*+ " start."*/);
            const std::string &type = attributes.getValue(CPackage::namespaceURI, CPackage::attributeType);
            
            assert(m_currentStanzaHandler.empty());
            GetStanzaHandler(type, m_currentStanzaHandler);
            m_handlerManager->GetStanzaHandler(type, m_currentStanzaHandler);
        }
        
        for (size_t i = 0; i < m_currentStanzaHandler.size(); i++)
            m_currentStanzaHandler[i]->startElement(m_attachedConnection, uri, localName, qname, attributes);
        
        
    }

    void CCoreXMLHandler::endElement(const XMLString& uri, const XMLString& localName, const XMLString& qname)
    {
        for (size_t i = 0; i < m_currentStanzaHandler.size(); i++)
            m_currentStanzaHandler[i]->endElement(m_attachedConnection, uri, localName, qname);

        if (localName == CPackage::labelExamination)
        {
            m_flagStreamStart = false;
            eventStreamEnd(this, nullInterger);
            systemLogger.trace("Stream end.");
        }
        else if (localName == CPackage::labelPackage)
        {
            //systemLogger.trace("Package: " + attributes.getValue(CPackage::namespaceURI, CPackage::attributeType) /*+ " start."*/);
            m_currentStanzaHandler.clear();            
        }
        else
        {
            // TODO: should we log this?
        }        
    }

    void CCoreXMLHandler::characters(const XMLChar ch[], int start, int length)
    {
        for (size_t i = 0; i < m_currentStanzaHandler.size(); i++)
            m_currentStanzaHandler[i]->characters(m_attachedConnection, ch, start, length);
    }

    void CCoreXMLHandler::ignorableWhitespace(const XMLChar ch[], int start, int length)
    {

    }

    void CCoreXMLHandler::processingInstruction(const XMLString& target, const XMLString& data)
    {

    }

    void CCoreXMLHandler::startPrefixMapping(const XMLString& prefix, const XMLString& uri)
    {

    }

    void CCoreXMLHandler::endPrefixMapping(const XMLString& prefix)
    {

    }

    void CCoreXMLHandler::skippedEntity(const XMLString& name)
    {

    }

    void CCoreXMLHandler::RegisterStanzaHandler(const std::string &type, CStanzaHandler *handler)
    {
        m_registeredHandlers.insert(std::make_pair(type, handler));
    }

    void CCoreXMLHandler::GetStanzaHandler(const std::string &type, std::vector<CStanzaHandler *> &handlers) const
    {
        std::multimap<std::string, CStanzaHandler *>::const_iterator it = m_registeredHandlers.lower_bound(type);
        std::multimap<std::string, CStanzaHandler *>::const_iterator itEnd = m_registeredHandlers.upper_bound(type);
        for (; it != itEnd; it++)
            handlers.push_back(it->second);
    }

    void CCoreXMLHandler::AttachToConnection(CXMLConnection *connection)
    {
        m_attachedConnection = connection;
    }

}